package com.atguigu;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

//https://cloud.tencent.com/developer/article/2555904
//https://blog.csdn.net/q343509740/article/details/147171384
//https://blog.csdn.net/jam_yin/article/details/149709438
public class StreamDetailedExample {
    public static void main(String[] args) {
        // 准备测试数据：产品列表
        List<Product> products = Arrays.asList(
            new Product("Laptop", "Electronics", 999.99, 10),
            new Product("Smartphone", "Electronics", 699.99, 25),
            new Product("Shirt", "Clothing", 29.99, 50),
            new Product("Pants", "Clothing", 49.99, 30),
            new Product("Headphones", "Electronics", 199.99, 15),
            new Product("Socks", "Clothing", 9.99, 100),
            new Product("Laptop", "Electronics", 1299.99, 5) // 重复名称的产品
        );

        // 1. 筛选与切片操作
        System.out.println("=== 筛选价格>100的电子产品 ===");
        List<Product> expensiveElectronics = products.stream()
            .filter(p -> "Electronics".equals(p.getCategory())) // 筛选电子产品
            .filter(p -> p.getPrice() > 100) // 筛选价格>100
            .distinct() // 去重（需重写Product的equals和hashCode）
            .skip(1) // 跳过第一个元素
            .limit(2) // 只取前2个元素
            .collect(Collectors.toList());

        expensiveElectronics.forEach(System.out::println);

        // 2. 映射操作
        System.out.println("\n=== 提取所有产品名称并转为大写 ===");
        List<String> upperCaseNames = products.stream()
            .map(Product::getName) // 提取名称（映射为String流）
            .map(String::toUpperCase) // 转为大写
            .collect(Collectors.toList());

        System.out.println(upperCaseNames);

        // 3. 排序操作
        System.out.println("\n=== 按价格升序排序（价格相同按库存降序） ===");
        List<Product> sortedProducts = products.stream()
            .sorted(Comparator.comparingDouble(Product::getPrice) // 主排序：价格升序
                .thenComparing(Comparator.comparingInt(Product::getStock).reversed())) // 次排序：库存降序
            .collect(Collectors.toList());

        sortedProducts.forEach(p -> System.out.printf("%.2f -> %s%n", p.getPrice(), p.getName()));

        // 4. 查找与匹配
        System.out.println("\n=== 查找与匹配示例 ===");
        boolean hasCheapClothing = products.stream()
            .anyMatch(p -> "Clothing".equals(p.getCategory()) && p.getPrice() < 10); // 是否有便宜服装
        System.out.println("有价格<10的服装？ " + hasCheapClothing);

        boolean allElectronicsExpensive = products.stream()
            .filter(p -> "Electronics".equals(p.getCategory()))
            .allMatch(p -> p.getPrice() > 100); // 所有电子产品都>100？
        System.out.println("所有电子产品价格都>100？ " + allElectronicsExpensive);

        Optional<Product> firstExpensiveProduct = products.stream()
            .filter(p -> p.getPrice() > 1000)
            .findFirst(); // 查找第一个价格>1000的产品
        firstExpensiveProduct.ifPresent(p -> System.out.println("第一个高价产品：" + p.getName()));

        // 5. 归约操作
        System.out.println("\n=== 归约操作示例 ===");
        // 计算所有电子产品的总库存
        int totalElectronicsStock = products.stream()
            .filter(p -> "Electronics".equals(p.getCategory()))
            .mapToInt(Product::getStock) // 转为IntStream
            .sum(); // 求和（简化的归约）
        System.out.println("电子产品总库存：" + totalElectronicsStock);

        // 计算所有产品的总价值（价格*库存）
        double totalValue = products.stream()
            .mapToDouble(p -> p.getPrice() * p.getStock())
            .reduce(0.0, Double::sum); // 归约求和
        System.out.printf("所有产品总价值：%.2f%n", totalValue);

        // 6. 收集操作（高级分组与统计）
        System.out.println("\n=== 高级收集操作 ===");
        // 按类别分组，并统计每个类别的产品数量
        Map<String, Long> productsByCategory = products.stream()
            .collect(Collectors.groupingBy(
                Product::getCategory,
                Collectors.counting() // 下游收集器：计数
            ));
        System.out.println("按类别分组的产品数量：" + productsByCategory);

        // 按类别分组，并计算每个类别的平均价格
        Map<String, Double> avgPriceByCategory = products.stream()
            .collect(Collectors.groupingBy(
                Product::getCategory,
                Collectors.averagingDouble(Product::getPrice) // 下游收集器：计算平均值
            ));
        System.out.println("按类别分组的平均价格：" + avgPriceByCategory);

        // 7. 并行流操作（处理大数据时提高效率）
        System.out.println("\n=== 并行流操作 ===");
        long startTime = System.currentTimeMillis();
        // 并行计算所有产品价格总和（模拟大数据量场景）
        double parallelSum = products.parallelStream() // 获取并行流
            .mapToDouble(Product::getPrice)
            .sum();
        long endTime = System.currentTimeMillis();
        System.out.printf("并行流计算价格总和：%.2f（耗时：%dms）%n", parallelSum, (endTime - startTime));

        List<Product> list1 = new ArrayList<>();
        List<Product> list2 = new ArrayList<>();
        Stream.concat(list1.stream(),list2.stream())
                .sorted(Comparator.comparing(Product::getId))
                .skip(2)
                .limit(2)
                .toList();

    }

    // 产品类（用于测试
    static class Product {
        private Long id;
        private String name;
        private String category;
        private double price;
        private int stock;

        public Product(String name, String category, double price, int stock) {
            this.name = name;
            this.category = category;
            this.price = price;
            this.stock = stock;
        }

        // getter方法
        public Long getId() {return id;}
        public String getName() { return name; }
        public String getCategory() { return category; }
        public double getPrice() { return price; }
        public int getStock() { return stock; }

        // 重写equals和hashCode用于distinct()去重
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }
            Product product = (Product) o;
            return Objects.equals(name, product.name) &&
                   Objects.equals(category, product.category);
        }

        @Override
        public int hashCode() {
            return Objects.hash(name, category);
        }

        @Override
        public String toString() {
            return String.format("%s (%s): $%.2f, 库存: %d", name, category, price, stock);
        }
    }
}